/**
 * BCGameButton
 * 自定义按钮组件
 * 功能：
 * 		1.支持连击
 * 		2.支持按下、抬起、取消音效
 * 		3.支持点击缩放
 * 		4.支持点击换图
 * 		5.支持点击换颜色
 */

import { _decorator, Component, Node, AudioClip, Sprite, Color, color, SpriteFrame, warn, UITransform, v3, macro, Label } from 'cc';
import { EDITOR } from 'cc/env';
import { BCAudioMgr } from '../../controller/BCAudioMgr';
const { ccclass, property } = _decorator;

@ccclass('AudioName')
class AudioName {
	@property({ type: AudioClip, displayName: '按下', tooltip: '按下时触发' })
	m_press: AudioClip = null;
	@property({ type: AudioClip, displayName: '抬起', tooltip: '抬起时触发' })
	m_release: AudioClip = null;
	@property({ type: AudioClip, displayName: '取消', tooltip: '按钮外抬起时触发' })
	m_cancel: AudioClip = null;
}

@ccclass('BCGameButton')
export default class BCGameButton extends Component {

	private _isActive: boolean = true;
	@property({ displayName: '是否激活' })
	get isActive() { return this._isActive; }
	set isActive(value: boolean) {
		this._isActive = value;
		this._updateActive();
	}
	@property({ displayName: '是否连发', tooltip: '不需要连发的按钮，可以关闭连发减小开销' })
	private m_isBurst: boolean = false;

	@property({ min: 0, displayName: '连发延迟时间（秒）', tooltip: '按下几秒后开始连发', visible() { return this.m_isBurst } })
	private m_delayTime: number = 0;

	@property({ min: 0, displayName: '连发间隔（秒）', tooltip: '每隔几秒触发一次', visible() { return this.m_isBurst } })
	private m_intervalTime: number = 0.1;

	@property({ min: 0, displayName: '按下后缩放' })
	private m_pressScale: number = 0.9;

	@property({ displayName: '按下后变色' })
	private m_pressedColor: Color =color(255, 255, 255);

	@property({ displayName: '禁用后变色' })
	private m_disableColor: Color = color(100, 100, 100);

	@property({ type: Node, displayName: '换图节点', tooltip: '换图动画作用于哪个节点' })
	private m_effectNode: Node = null;

	@property({ type: SpriteFrame, displayName: '按下后换图', visible() { return this.m_effectNode !== null } })
	private m_pressedFrame: SpriteFrame = null;

	@property({ type: SpriteFrame, displayName: '禁用后换图', visible() { return this.m_effectNode !== null } })
	private m_disableFrame: SpriteFrame = null;

	@property({ type: AudioName, displayName: '音效', tooltip: '把需要播放的音效文件拖进来' })
	private m_audio: AudioName = new AudioName();


	private m_effectSprite: Sprite = null;
	private m_normalScale: number = 1;
	private m_normalFrame: SpriteFrame = null;
	private m_callback: (tag: string, event: string, ...parms: any[]) => void = () => { };
	private _warn = EDITOR ? warn : console.warn;

	protected start() {
		this.name = this.node.name;
		this.m_normalScale = this.node.scale.x;
		if (this.m_effectNode) {
			this.m_effectSprite = this.m_effectNode.getComponent(Sprite);
			this.m_normalFrame = this.m_effectSprite?.spriteFrame;
		}
		
		const uiTrans = this.node.getComponent(UITransform);
		if (uiTrans.width === 0 || uiTrans.height === 0) {
			this._warn(`按钮宽/高为0，无法响应触摸事件！(${this.node?.parent?.parent.name}/${this.node?.parent.name}/${this.node.name})`);
		}
		if (this.m_effectNode && this.m_effectSprite === null) {
			this._warn(`按钮换图节点没有cc.Sprite，无法换图！(${this.node?.parent?.parent.name}/${this.node?.parent.name}/${this.node.name})`);
		}
		this._updateActive();
	}

	setCallback(callback: (tag: string, event: string, ...parms: any[]) => void, bind: any) {
		this.m_callback = callback.bind(bind);
	}

	private _updateActive() {
		if (this.isActive) {
			this.setColor(this.node, color(255, 255, 255));
			this.m_effectSprite && (this.m_effectSprite.spriteFrame = this.m_normalFrame);
			this.node.on(Node.EventType.TOUCH_START, this._touchStart, this);
			this.node.on(Node.EventType.TOUCH_END, this._touchEnd, this);
			this.node.on(Node.EventType.TOUCH_CANCEL, this._touchCancel, this);
		} else {
			this.setColor(this.node, this.m_disableColor);
			this.m_disableFrame && (this.m_effectSprite.spriteFrame = this.m_disableFrame);
			this.m_isBurst && this.unschedule(this.touchBurst);
			this.node.targetOff(this);
			this.node.scale = v3(this.m_normalScale, this.m_normalScale, 1);
		}
	}

	private touchBurst() {
		this.m_callback(this.node.name, 'burst', this);
	}

	private _touchStart() {
		this.m_isBurst && this.schedule(this.touchBurst, this.m_intervalTime, macro.REPEAT_FOREVER, this.m_delayTime);
		this.setColor(this.node, this.m_pressedColor);
		this.m_pressedFrame && (this.m_effectSprite.spriteFrame = this.m_pressedFrame);

		const scale = this.m_pressScale * this.m_normalScale;
		this.node.scale = v3(scale, scale, 1);
		this.m_audio.m_press && BCAudioMgr.instance.playSound(this.m_audio.m_press, this.node);
		this.m_callback(this.node.name, 'press', this);
	}

	private _touchEnd() {
		this.m_isBurst && this.unschedule(this.touchBurst);
		this.setColor(this.node, color(255, 255, 255));
		this.m_effectSprite && (this.m_effectSprite.spriteFrame = this.m_normalFrame);
		this.node.scale = v3(this.m_normalScale, this.m_normalScale, 1);
		this.m_audio.m_release && BCAudioMgr.instance.playSound(this.m_audio.m_release, this.node);
		this.m_callback(this.node.name, 'release', this);
	}

	private _touchCancel() {
		this.m_isBurst && this.unschedule(this.touchBurst);
		this.setColor(this.node,color(255, 255, 255));
		this.m_effectSprite && (this.m_effectSprite.spriteFrame = this.m_normalFrame);
		this.node.scale = v3(this.m_normalScale, this.m_normalScale, 1);
		this.m_audio.m_cancel && BCAudioMgr.instance.playSound(this.m_audio.m_cancel, this.node);
		this.m_callback(this.node.name, 'cancel', this);
	}

	private setColor(node: Node, color: Color) {
		const label = node.getComponent(Label);
		if(label){
			label.color = color
		} else {
			const sprite = node.getComponent(Sprite);
			sprite && (sprite.color = color);
		}
		for (let i = node.children.length - 1; i > -1; this.setColor(node.children[i--], color));
	}

	protected onDestroy() {
		this.node.targetOff(this);
	}
}
